/* ========================================
 *
 * Copyright Nano IC, 2021-02-25
 * All Rights Reserved
 * UNPUBLISHED, LICENSED SOFTWARE.
 *
 * CONFIDENTIAL AND PROPRIETARY INFORMATION
 * WHICH IS THE PROPERTY OF Nano IC.
 *
 * ========================================
*/

#include "one_wire_bus_tra.h"

void InvertUint16(uint16_t *val,uint16_t *data)
{
	
	uint8_t temp=0;
	 uint16_t dat=0;
	 temp = (*val >> 8) & 0xff;
	 dat |= temp << 0;
	 temp = (*val) & 0xff;
	 dat |= temp << 8;
	 
	 *data=dat;
}

// 反转一个字节
uint8_t reflect8(uint8_t data) {
    uint8_t result = 0;
    for (int i = 0; i < 8; i++) {
        result <<= 1;
        result |= (data & 1);
        data >>= 1;
    }
    return result;
}


// CRC-16 CCITT多项式：0x1021
#define POLY 0x1021
 
// 计算CRC-16 CCITT
unsigned short crc16_ccitt( unsigned char *data, unsigned short len) 
{
    unsigned short crc = 0x0000;  // 初始值
    while (len--) {
        crc ^= *data++ << 8;  // 将数据左移8位与CRC寄存器进行异或
        for (int i = 0; i < 8; i++) {
            if (crc & 0x8000) {
                crc = (crc << 1) ^ POLY;
            } else {
                crc = crc << 1;
            }
        }
    }
    return crc;  // 返回最终的CRC值
}

//unsigned short crc16_ccitt(unsigned char *data, unsigned int datalen)
//{
//	unsigned short wCRCin = 0x0000;
//	unsigned short wCPoly = 0x1021;
//	unsigned char wchar =0;
//	InvertUint16(&wCPoly,&wCPoly);
//	while(datalen--)
//	{
//		wCRCin ^=*(data++);
//		for(int i=0;i< 8;i++)
//		{
//			if(wCRCin & 0x01)
//				wCRCin=(wCRCin>>1)^wCPoly;
//			else
//				wCRCin =wCRCin >>1;
//		}
//
//	
//	}
//	return(wCRCin);
//}



extern uint8_t one_wire_bus_phy_rec_buf[ONE_WIRE_PHY_FRAME_REC_MAX_LENGTH];
extern uint8_t one_wire_bus_phy_send_buf[ONE_WIRE_PHY_FRAME_SEND_MAX_LENGTH];
extern bool one_wrie_bus_app_rec_frame_callback(OneWirePacketStr *p_rec_packet);

#define RANDOM_NUM (rand() % 100 + 1)   //返回随机数的值1-100


// 单总线每Byte消耗时间11.88uS，250Byte消耗时间: 250*11.88uS = 2.97mS
uint8_t send_long_one_wire_queue_buffer[SEND_LONG_ONE_WIRE_BLOCK_NUMBER][SEND_LONG_ONE_WIRE_BLOCK_QUEUE_LENGTH];
uint8_t send_short_one_wire_queue_buffer[SEND_SHORT_ONE_WIRE_BLOCK_NUMBER][SEND_SHORT_ONE_WIRE_BLOCK_QUEUE_LENGTH];
uint8_t send_ack_one_wire_queue_buffer[SEND_ACK_ONE_WIRE_BLOCK_NUMBER][SEND_ACK_ONE_WIRE_BLOCK_QUEUE_LENGTH];
//uint8_t rec_one_wire_queue_buffer[REC_ONE_WIRE_BLOCK_NUMBER][REC_ONE_WIRE_BLOCK_QUEUE_LENGTH];
BlockQueueStruct send_long_one_wire_queue;
BlockQueueStruct send_short_one_wire_queue;
//BlockQueueStruct rec_one_wire_queue;
BlockQueueStruct send_ack_wire_queue;

SourcePacketStr *p_source_packet;       // 源数据包
DisturbPacketStr *p_disturb_packet;     // 加扰数据包
ConvertPacketStr *p_convert_packet;     // 转码数据包
OneWirePacketStr *p_one_wire_packet;    // 单线数据包

volatile uint8_t one_wire_tra_tmp_buf[SEND_LONG_ONE_WIRE_BLOCK_QUEUE_LENGTH];

/*  ========================== Nano IC =========================
 *                                                              *
 *   The transport layer application functions are as follows   *
 *                                                              *
 *  ============================================================
*/
/**
 * @brief :单总线转输层协议初始化
 * 
 * @param 
 * @return true : 成功
 * @return false : 失败
 */
bool one_wire_bus_tra_init(void)
{
    bool flag1,flag2,flag3;

    one_wire_bus_phy_init(); 
    flag1 = block_queue_create(&send_long_one_wire_queue , 
                            (uint8_t *)&send_long_one_wire_queue_buffer[0][0] ,
                            SEND_LONG_ONE_WIRE_BLOCK_QUEUE_LENGTH, 
                            SEND_LONG_ONE_WIRE_BLOCK_NUMBER
                            );

    flag2 = block_queue_create(&send_short_one_wire_queue , 
                            (uint8_t *)&send_short_one_wire_queue_buffer[0][0] ,
                            SEND_SHORT_ONE_WIRE_BLOCK_QUEUE_LENGTH, 
                            SEND_SHORT_ONE_WIRE_BLOCK_NUMBER
                            );                            

//    flag3 = block_queue_create(&rec_one_wire_queue , 
//                            (uint8_t *)&rec_one_wire_queue_buffer[0][0] ,
//                            SEND_SHORT_ONE_WIRE_BLOCK_QUEUE_LENGTH, 
//                            SEND_SHORT_ONE_WIRE_BLOCK_QUEUE_LENGTH
//                            );
	flag2 = block_queue_create(&send_ack_wire_queue , 
						(uint8_t *)&send_ack_one_wire_queue_buffer[0][0] ,
						SEND_ACK_ONE_WIRE_BLOCK_QUEUE_LENGTH, 
						SEND_ACK_ONE_WIRE_BLOCK_NUMBER
						);
    return (flag1 && flag2/* && flag3*/);
}

volatile uint8_t deb_out_len_buf[9] = {0};
/* @brief 数据加扰算法
 * 
 * @return 返回数据长度
 */
uint8_t one_wire_bus_tra_data_disturb(uint8_t * p_in_buf, uint8_t * p_out_buf, uint8_t len, uint8_t random_number)
{
    for(uint8_t i = 0; i<len; i++)
    {
        p_out_buf[i] = p_in_buf[i] ;
    }
    return len;
}

/* @brief 将要发送的数据、命令，打包成源数据包
 * 
 * @return 返回打包后的数据长度
 */
uint8_t one_wire_bus_tra_pack_source_frame(uint8_t *pdata,uint8_t len,uint8_t cmd,uint8_t serial)
{
	#if 0
     /*  从第B[6]开始，预留4Byt同步字，1Byte起始位, 1Byte随机数 */
    p_source_packet = (SourcePacketStr *)&one_wire_tra_tmp_buf[ONE_WIRE_SOURCE_BUF_ADDR];  // B[5]
   
    p_source_packet->len = len;
    if(p_source_packet->len > ONE_WIRE_BUS_PACKET_MAX_DATA_LEN)
    {
        p_source_packet->len = ONE_WIRE_BUS_PACKET_MAX_DATA_LEN;
    }
    p_source_packet->cmd = cmd;
    p_source_packet->serial = serial;
    for(uint8_t i=0;i<len;i++)
    {
        p_source_packet->data[i] = pdata[i];
    }
    p_source_packet->data[p_source_packet->len] = 
                one_wire_bus_get_buf_sum((uint8_t *)&p_source_packet->len,p_source_packet->len + 3);
    deb_out_len_buf[3] = len+4;
    return (len+4);
	#endif
}

/* @brief 将要发送的数据、命令，转换成加扰后的数据包
 * 
 * @return 返回加扰后的数据长度
 */
uint8_t one_wire_bus_tra_pack_disturb_frame(uint8_t *pdata,uint8_t len,uint8_t cmd,uint8_t serial,uint8_t random_num)
{
	#if 0
    uint8_t out_len;
    out_len = one_wire_bus_tra_pack_source_frame(pdata,len,cmd,serial);
    one_wire_bus_tra_data_disturb((uint8_t *)&p_disturb_packet->src_packet.len, 
                                        (uint8_t *)&p_disturb_packet->src_packet.len, 
                                        out_len, 
                                        0x00 // p_disturb_packet->random_num
                                        );
    deb_out_len_buf[4] = out_len + 1;
    return (out_len);
	#endif
}

/* @brief 将要发送的数据、命令，转换成转码数据包
 * 
 * @return 返回转码数据长度
 */
uint8_t one_wire_bus_tra_pack_convert_frame(uint8_t *pdata,uint8_t len,uint8_t cmd,uint8_t serial)
{
	#if 0
    uint8_t out_len,conver_len;
    uint8_t random_num = 0x35;    
    out_len = one_wire_bus_tra_pack_disturb_frame(pdata,len,cmd,serial,random_num);
    conver_len = out_len;
    deb_out_len_buf[5] = conver_len;
    return conver_len;
	#endif
}

/* @brief 将要发送的数据、命令，转换成单总线数据包
 * 
 * @return 返回单总线数据长度
 */
 

uint8_t one_wire_bus_tra_pack_uart_frame(uint8_t *pdata,uint16_t len,flagbody *flag,uint16_t serial,uint16_t remoteSerial)
{
    uint8_t out_len;
    p_one_wire_packet = (OneWirePacketStr *)&one_wire_tra_tmp_buf[ONE_WIRE_PACKET_BUF_ADDR];

    /*  同步字最少2Byte，一般是4Byte开始  */
    one_wire_tra_tmp_buf[0] = ONE_WIRE_BUS_PACKET_SYNC_WORD;
    one_wire_tra_tmp_buf[1] = ONE_WIRE_BUS_PACKET_SYNC_WORD;
	one_wire_tra_tmp_buf[2] = ONE_WIRE_BUS_PACKET_SYNC_WORD;
    one_wire_tra_tmp_buf[3] = ONE_WIRE_BUS_PACKET_SYNC_WORD;
	
	p_one_wire_packet->len = len+8;
	memcpy(&(p_one_wire_packet->flag),flag,sizeof(flagbody));
    p_one_wire_packet->seriallumber = serial;
    p_one_wire_packet->remoteSeriallumber = remoteSerial;
	
	for(uint16_t i=0;i<len;i++)
	{
		p_one_wire_packet->convert.cover_data[i] = pdata[i];
	}
	uint16_t crc16 = crc16_ccitt((uint8_t*)&one_wire_tra_tmp_buf[4],p_one_wire_packet->len);

    p_one_wire_packet->convert.cover_data[len] = crc16;
    p_one_wire_packet->convert.cover_data[len+1] = crc16>>8;
    p_one_wire_packet->convert.cover_data[len+2] = ONE_WIRE_BUS_PACKET_START_END_FLAG;
    p_one_wire_packet->convert.cover_data[len+3] = ONE_WIRE_BUS_PACKET_START_END_FLAG2;
	
	out_len=p_one_wire_packet->len+8;
	
    return out_len;
}
//-------------------------------------------------------------------------------------------
/* @brief 将要发送的数据、命令，转成标准格式，并写入队列
 * 
 * @param pdata : 要写入的数据，最大长度64Byte
 * @param len : 写入的数据长度
 * @param cmd : 要写入的命令字
 * @param serial : 流水号
 * @param f_irq_dis : 写入队列时是否关中断
 * 
 * @return true : 写入成功
 * @return false : 写入失败
 */
bool one_wire_bus_tra_write_long_frame_to_queue(uint8_t *pdata,uint8_t len,flagbody *flag_data,uint8_t serial,uint8_t remoteSerial,bool f_irq_dis)
{
	#if 0
    bool flag;
    uint8_t out_len;
    out_len = one_wire_bus_tra_pack_uart_frame(pdata,len,serial,remoteSerial);
    flag = block_queue_write(&send_long_one_wire_queue , 
                                (uint8_t *)&one_wire_tra_tmp_buf[0] , 
                                out_len , 
                                f_irq_dis
                                );
    return flag;
	#endif
}
bool one_wire_bus_tra_write_long_frame_to_queue_aaa(uint8_t *pdata,uint16_t len,flagbody *flag_data,uint16_t serial,uint16_t remoteSerial,bool f_irq_dis)
{
   bool flag;
    uint8_t out_len;
    out_len = one_wire_bus_tra_pack_uart_frame(pdata,len,flag_data,serial,remoteSerial);

    flag = block_queue_write(&send_long_one_wire_queue , 
                                (uint8_t *)&one_wire_tra_tmp_buf[0] , 
                                out_len , 
                                f_irq_dis
                                );
    return flag;	
}
/* @brief 将要发送的数据、命令，转成标准格式，并写入队列
 * 
 * @param pdata : 要写入的数据，最大长度32Byte
 * @param len : 写入的数据长度
 * @param cmd : 要写入的命令字
 * @param serial : 流水号
 * @param f_irq_dis : 写入队列时是否关中断
 * 
 * @return true : 写入成功
 * @return false : 写入失败
 */
bool one_wire_bus_tra_write_short_frame_to_queue(uint8_t *pdata,uint16_t len,flagbody *flag_data,uint16_t serial,uint16_t remoteSerial,bool f_irq_dis)
{
    bool flag;
    uint8_t out_len;
    out_len = one_wire_bus_tra_pack_uart_frame(pdata,len,flag_data,serial,remoteSerial);
    flag = block_queue_write(&send_short_one_wire_queue , 
                                (uint8_t *)&one_wire_tra_tmp_buf[0] , 
                                out_len , 
                                f_irq_dis
                                );
    return flag;
}
/* @brief 将要发送的数据、命令，转成标准格式，并写入队列
 * 
 * @param pdata : 要写入的数据，最大长度32Byte
 * @param len : 写入的数据长度
 * @param cmd : 要写入的命令字
 * @param serial : 流水号
 * @param f_irq_dis : 写入队列时是否关中断
 * 
 * @return true : 写入成功
 * @return false : 写入失败
 */
bool one_wire_bus_tra_write_ack_frame_to_queue(uint8_t *pdata,uint16_t len,flagbody *flag_data,uint16_t serial,uint16_t remoteSerial,bool f_irq_dis)
{
    bool flag;
    uint8_t out_len;
    out_len = one_wire_bus_tra_pack_uart_frame(pdata,len,flag_data,serial,remoteSerial);
    flag = block_queue_write(&send_ack_wire_queue , 
                                (uint8_t *)&one_wire_tra_tmp_buf[0] , 
                                out_len , 
                                f_irq_dis
                                );
    return flag;
}
/* @brief 从队列中读取数据、命令，并打包成一帧串口要发送的数据
 * 
 * @return uint8_t : 最终打包完成，需要串口发送的数据长度
 */
uint16_t one_wire_bus_tra_read_queue_pack_uart_frame(void)
{
    uint8_t *pbuf;
    bool f_queue_empty;
    uint16_t cur_len,write_len;
    uint8_t num;

    write_len = 0x00;
    pbuf = (uint8_t *)&one_wire_bus_phy_send_buf[0];
	f_queue_empty = block_queue_is_empty(&send_ack_wire_queue);
	if(f_queue_empty == false)
	{  // 队列中有数据
		cur_len = block_queue_next_block_length(&send_ack_wire_queue);
		if((write_len + cur_len) < ONE_WIRE_PHY_FRAME_SEND_MAX_LENGTH)
		{ // 将要读取的队列块中数据，不超过缓冲区余量                
			uint16_t buf_len,read_len;
			buf_len = ONE_WIRE_PHY_FRAME_SEND_MAX_LENGTH - write_len;
			read_len = block_queue_read(&send_ack_wire_queue, pbuf , buf_len , true);
			pbuf += read_len;
			write_len += read_len;
			return write_len;
		}
	}

	f_queue_empty = block_queue_is_empty(&send_short_one_wire_queue);
	if(f_queue_empty == false)
	{  // 队列中有数据
		cur_len = block_queue_next_block_length(&send_short_one_wire_queue);
		if((write_len + cur_len) < ONE_WIRE_PHY_FRAME_SEND_MAX_LENGTH)
		{ // 将要读取的队列块中数据，不超过缓冲区余量                
			uint16_t buf_len,read_len;
			buf_len = ONE_WIRE_PHY_FRAME_SEND_MAX_LENGTH - write_len;
			read_len = block_queue_read(&send_short_one_wire_queue, pbuf , buf_len , true);
			pbuf += read_len;
			write_len += read_len;
		}
	}else{
		f_queue_empty = block_queue_is_empty(&send_long_one_wire_queue);
		if(f_queue_empty == false)
		{  // 队列中有数据
			cur_len = block_queue_next_block_length(&send_long_one_wire_queue);
			if((write_len + cur_len) < ONE_WIRE_PHY_FRAME_SEND_MAX_LENGTH)
			{ // 将要读取的队列块中数据，不超过缓冲区余量
				uint16_t buf_len,read_len;
				buf_len = ONE_WIRE_PHY_FRAME_SEND_MAX_LENGTH - write_len;
				read_len = block_queue_read(&send_long_one_wire_queue, pbuf , buf_len , true);
				pbuf += read_len;
				write_len += read_len;
			}
		}
	}
	
	
//    f_queue_empty = block_queue_is_empty(&send_long_one_wire_queue);
//    if(f_queue_empty == false)
//    {  // 队列中有数据
//        cur_len = block_queue_next_block_length(&send_long_one_wire_queue);
//        if((write_len + cur_len) < ONE_WIRE_PHY_FRAME_SEND_MAX_LENGTH)
//        { // 将要读取的队列块中数据，不超过缓冲区余量
//            uint16_t buf_len,read_len;
//            buf_len = ONE_WIRE_PHY_FRAME_SEND_MAX_LENGTH - write_len;
//            read_len = block_queue_read(&send_long_one_wire_queue, pbuf , buf_len , true);
//            pbuf += read_len;
//            write_len += read_len;
//        }
//    }else{
//        f_queue_empty = block_queue_is_empty(&send_short_one_wire_queue);
//        if(f_queue_empty == false)
//        {  // 队列中有数据
//            cur_len = block_queue_next_block_length(&send_short_one_wire_queue);
//            if((write_len + cur_len) < ONE_WIRE_PHY_FRAME_SEND_MAX_LENGTH)
//            { // 将要读取的队列块中数据，不超过缓冲区余量                
//                uint16_t buf_len,read_len;
//                buf_len = ONE_WIRE_PHY_FRAME_SEND_MAX_LENGTH - write_len;
//                read_len = block_queue_read(&send_short_one_wire_queue, pbuf , buf_len , true);
//                pbuf += read_len;
//                write_len += read_len;
//            }
//        }
//    }
    return write_len;
}
//-------------------------------------------------------------------------------------------
/**
 * @brief 1. 串口连续23uS(2 Byte对应时间)未收到数据，表示一帧接收完成，调用一次本函数。
 * @brief 2. 由于单总线协议规定了串口数据传输间隔，若芯片硬件不支持23uS串口超时中断，可用
 * @brief    定时器控制串口接收超时，可以超时 500mS 来实现。
 * @brief 3. 串口会接收到对方数据，也会接收到自已发送的数据，可能是一个包，也可能是多包接连，
 * @brief 4. 串口接收缓冲最大长度200 Byte
 * 
 * @param p_uart_data ：串口接收数据指针
 * @param rec_len ： 串口接收到的数据长度
 * 
 * @return 
 */
void one_wire_bus_tra_rec_callback(uint8_t *p_uart_data,uint16_t rec_len)
{
    uint16_t search_addr;
	uint16_t data_len=rec_len;
    if(data_len > ONE_WIRE_PHY_FRAME_REC_MAX_LENGTH)
    {
        data_len = ONE_WIRE_PHY_FRAME_REC_MAX_LENGTH;
    }
	//memcpy(one_wire_bus_phy_rec_buf,p_uart_data,data_len);
	if(one_wire_bus_phy_rec_callback(p_uart_data,data_len))		//自发自收数据，不再向下进行解析
		return;
    /* 遍历串口接收到的数据包，找到用用数据包 */
    search_addr = 0;
    for(uint8_t frames=0; frames<ONE_WIRE_PACKET_MAX_FRAME_NUM; frames++)
    {
        uint16_t frame_head_addr,frame_end_addr;
        uint8_t get_frame_flag;

        get_frame_flag = 0;
        frame_head_addr = 0;
        frame_end_addr = 0;
        for(;search_addr<data_len;search_addr++)
        {
            if((one_wire_bus_phy_rec_buf[search_addr] == ONE_WIRE_BUS_PACKET_SYNC_WORD)
                    &&(one_wire_bus_phy_rec_buf[search_addr + 1] == ONE_WIRE_BUS_PACKET_SYNC_WORD)
                    &&(one_wire_bus_phy_rec_buf[search_addr + 2] == ONE_WIRE_BUS_PACKET_SYNC_WORD)
					&&(one_wire_bus_phy_rec_buf[search_addr + 3] == ONE_WIRE_BUS_PACKET_SYNC_WORD)
                    )
            {  // 搜索到“通信包启始”位                
                uint16_t frame_len;
                frame_len = one_wire_bus_phy_rec_buf[search_addr + 4] + one_wire_bus_phy_rec_buf[search_addr + 5]*256;  // one_wire_bus_tra_pack_get_length(&p_uart_data[search_addr + 2]);

                if((search_addr + frame_len + 4) <= data_len)
                {
                    if((one_wire_bus_phy_rec_buf[search_addr + frame_len + 6] == ONE_WIRE_BUS_PACKET_START_END_FLAG)
						&&(one_wire_bus_phy_rec_buf[search_addr + frame_len + 7] == ONE_WIRE_BUS_PACKET_START_END_FLAG2))
                    {
                        get_frame_flag = 1;
                        frame_head_addr = search_addr + 4;
                        frame_end_addr = search_addr + frame_len + 4;
                        break;
                    }                                                                                                                                                                                                                                                                                          
                }
            }
        }

        if((get_frame_flag == 1)&&(frame_end_addr <= data_len))
        {            
            bool frame_ok;
            frame_ok = one_wire_bus_tra_analysis_rec_packet(
                                    (uint8_t *)&one_wire_bus_phy_rec_buf[frame_head_addr],
                                    (uint8_t *)&one_wire_bus_phy_rec_buf[frame_end_addr]
                                    );
            if(frame_ok)
            {
                search_addr = frame_end_addr + 1;

            }
		
            get_frame_flag = 0;
            frame_head_addr = 0;
            frame_end_addr = 0;
        }
    }
}

/**
 * @brief 从串口中拆分出一帧单总线数据包，并作相应处理
 * 
 * @param p_udata_start ：一帧单总线数据包数据启始指针
 * @param p_udata_end ： 一帧单总线数据结束指针
 * 
 * @return true:操作成功  false:操作失败
 */
uint16_t deb_back_start_end[2] = {0};


bool one_wire_bus_tra_analysis_rec_packet(uint8_t *p_udata_start,uint8_t *p_udata_end)
{
    uint32_t frame_in_len;    
    frame_in_len = (uint32_t)p_udata_end - (uint32_t)p_udata_start;
	
	uint16_t frame_len;
	frame_len = p_udata_start[0] + p_udata_start[1]*256; 
    if((frame_len==frame_in_len) && (frame_in_len <= REC_ONE_WIRE_BLOCK_QUEUE_LENGTH))
    {
        uint16_t check_sum,rd_sum;
        check_sum = crc16_ccitt(p_udata_start,frame_len);
        rd_sum = p_udata_end[0]+p_udata_end[1]*256;;
        if(rd_sum == check_sum)
        {
            one_wrie_bus_app_rec_frame_callback((OneWirePacketStr *)&p_udata_start[0]);
        }
        return true;
    }else{
//		printf("frame_in_len: %d frame_len: %d\n",frame_in_len,frame_len);
        return false;
    }
}
//-------------------------------------------------------------------------------------------
/**
 * @brief 检测自已接收到的数据，判断串口一个包是否发送成功
 *
 * @return 
 */ 
void one_wire_bus_tra_one_frame_send_ok(void)
{
    one_wire_bus_phy_set_send_status(true);
}

/**
 * @brief 单总线动行时钟基准，系统需要每0.5mS调用一次本函数
 */
void one_wire_bus_tra_timer_tick_process_0_5ms(void)
{
    one_wire_bus_phy_timer_tick_process_0_5ms();
}

//-------------------------------------------------------------------------------------------
/**
 * @brief 调试命令收发
 */
#ifdef ENABLE_ONE_WIRE_DEBUG_FUNCTION
bool one_wire_bus_tra_debug_function(void)
{
    uint16_t frame_len;
    frame_len = one_wire_bus_tra_read_queue_pack_uart_frame();

    one_wire_bus_tra_rec_callback((uint8_t *)&one_wire_bus_phy_send_buf[0],frame_len);
    
    return false;
}
#endif
//-------------------------------------------------------------------------------------------
/* [] END OF FILE */

